package com.hbx.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hbx.auth.AuthCacheService;
import com.hbx.constant.CachePrefixContent;
import com.hbx.constant.CommonContent;
import com.hbx.constant.DateFormatContent;
import com.hbx.constant.ReportResultEnum;
import com.hbx.constant.TableEnum;
import com.hbx.logs.annotation.MarkLog;
import com.hbx.logs.OperaTypeEnum;
import com.hbx.dto.report.HandlerReportDto;
import com.hbx.dto.report.ReportDetailVo;
import com.hbx.dto.report.ReportDto;
import com.hbx.dto.report.SearchReportDto;
import com.hbx.exception.RspException;
import com.hbx.mapper.RecycleBinMapper;
import com.hbx.mapper.ResourceMapper;
import com.hbx.model.Rank;
import com.hbx.model.RecycleBin;
import com.hbx.model.Report;
import com.hbx.mapper.ReportMapper;
import com.hbx.model.Resource;
import com.hbx.model.User;
import com.hbx.service.AsyncTaskService;
import com.hbx.service.RankService;
import com.hbx.service.ReportService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hbx.service.UserService;
import com.hbx.task.CompletableFutureService;
import com.hbx.utils.CacheUtils;
import com.hbx.utils.DateUtil;
import com.hbx.utils.MailSendUtil;
import com.hbx.utils.Result;
import com.hbx.utils.StringUtil;
import com.hbx.vo.PageBean;
import com.hbx.vo.PublicUserVo;
import com.hbx.vo.RankVo;
import com.hbx.vo.report.ReportListVo;
import com.hbx.vo.res.ResourceVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.mail.MessagingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author hbx
 * @since 2022-01-23
 */
@Service
@Slf4j
public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> implements ReportService {

    @Autowired
    private ReportMapper reportMapper;

    @Autowired
    private AsyncTaskService asyncTaskService;

    @Autowired
    private UserService userService;

    @Autowired
    private CacheUtils cacheUtils;

    @Autowired
    private RecycleBinMapper recycleBinMapper;

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private CompletableFutureService completableFutureService;

    @Autowired
    private MailSendUtil mailSendUtil;

    @Autowired
    private RankService rankService;

    /**
     * 添加举报信息
     * @param reportDto
     * @param r
     */
    @Override
    public void addReport(ReportDto reportDto, Result r) {
        Report report = new Report();
        User user = AuthCacheService.getUser();
        Set<String> results = cacheUtils.keys(CachePrefixContent.REPORT_COUNT + user.getUserId());
        if (!CollectionUtils.isEmpty(results) && results.size() >= 3){
            r.setCode(201).setMsg("举报失败,今日次数已超过最大限制");
            return;
        }
        BeanUtils.copyProperties(reportDto, report);
        report.setReportUserId(user.getUserId());
        List<String> images = reportDto.getReportImages();
        if (!CollectionUtils.isEmpty(images)){
            StringJoiner joiner = new StringJoiner(",");
            images.stream().forEach(img -> {
                joiner.add(img);
            });
            report.setReportImages(joiner.toString());
        }
        report.setReportPushTime(new Date());
        int insert = reportMapper.insert(report);
        if (insert != 1){
            r.setMsg("举报失败").setCode(201);
            return;
        }
        // 发邮件通知
        r.setCode(200).setMsg("举报成功");
        cacheUtils.set(CachePrefixContent.REPORT_COUNT + user.getUserId() + ":" + DateUtil.getDataTimeMillis(),
                DateUtil.getDataTimeMillis()
                , CommonContent.ONE_DAY_LONG);
        log.info("【举报模块】:举报信息添加成功");
        asyncTaskService.sendMailReport(reportDto, user);
    }

    /**
     * 管理员获得举报列表
     * @param dto
     * @param r
     */
    @Override
    public void reportList(SearchReportDto dto, Result r) {
        Page<Report> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        PageBean pageBean = new PageBean();
        String keyword = dto.getKeyword();
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("report_status");
        wrapper.orderByDesc("report_push_time");
        if (dto.getReportStatus() != null){
            wrapper.eq("report_status", dto.getReportStatus());
        }
        if (dto.getReportPushTime() != null){
            wrapper.eq("report_push_time", dto.getReportPushTime());
        }
        if (StringUtils.hasLength(keyword)){
            wrapper.like("report_type",keyword)
                    .or().like("report_why",keyword)
                    .or().like("report_result",keyword)
                    .or().like("report_beizhu",keyword);
        }

        IPage<Report> iPage = reportMapper.selectPage(page, wrapper);
        pageBean.setTotal(iPage.getTotal());
        pageBean.setPageNum(iPage.getCurrent());
        pageBean.setPageSize(iPage.getSize());
        List<Report> records = iPage.getRecords();
        if (CollectionUtils.isEmpty(records)){
            r.setCode(200).setMsg("暂无数据").setData(pageBean);
            return;
        }
        List<ReportListVo> list = new ArrayList<>();
        records.stream().forEach(record -> {
            ReportListVo vo = new ReportListVo();
            BeanUtils.copyProperties(record ,vo);
            if (record.getReportUserId() != null){
                User user = userService.getById(record.getReportUserId());
                if (user != null){
                    PublicUserVo userVo = new PublicUserVo();
                    userVo.setUserId(user.getUserId());
                    userVo.setUserName(user.getLoginName());
                    userVo.setAvatar(user.getAvator());
                    vo.setUserVo(userVo);
                }
            }
            list.add(vo);
        });
        pageBean.setData(list);
        r.setCode(200).setData(pageBean);
    }

    /**
     * 管理员处理举报
     * @param dto
     * @param r
     */
    @Override
    @Transactional
    @MarkLog(operate = OperaTypeEnum.UPDATE, tables = TableEnum.REPORT, desc = "管理员处理举报")
    public void handlerReport(HandlerReportDto dto, Result r) {

        User user = AuthCacheService.getUser();
        Integer handlerCode = dto.getHandlerCode();

        String result = ReportResultEnum.ReportResult(handlerCode);
        if(!StringUtils.hasLength(result)){
            r.setCode(201).setMsg("处理方式暂不支持");
            return;
        }
        Report report = reportMapper.selectById(dto.getId());
        if (report == null) {
            r.setCode(201).setMsg("举报信息不存在");
            return;
        }
        Integer resId = report.getResId();
        if (resId == null){
            r.setCode(201).setMsg("处理失败,资源已不存在");
            return;
        }
        Resource resource = resourceMapper.selectById(resId);
        if (resource == null){
            r.setCode(201).setMsg("处理失败,资源已不存在");
            return;
        }

        User resUser = userService.getById(resource.getResUserid());
        if (resUser == null){
            r.setCode(201).setMsg("处理失败,资源已不存在");
            return;
        }

        if (ReportResultEnum.REMOVE_RESOURCE.getCode().equals(handlerCode)){
            // 删除帖子
            removeResourceAndRecycle(resource, dto, r, user, report);
            // 处理举报信息表
            handlerReportInfo(dto, result,1,user);
        } else if (ReportResultEnum.REMOVE_RESOURCE_AND_WARN.getCode().equals(handlerCode)){
            // 删帖并警告用户
            // 删除帖子
            removeResourceAndRecycle(resource, dto, r, user, report);
            // 处理举报信息表
            handlerReportInfo(dto, result,1,user);
            // 警告用户
            String subject = "关于资源被举报处理通知";
            StringBuilder sb = new StringBuilder();
            sb.append("<div>资源标题:");
            sb.append(resource.getResTitle());
            sb.append("</div>");
            sb.append("<div>举报时间:");
            sb.append(DateUtil.dateToString(report.getReportPushTime(), DateFormatContent.YYYY_MM_DD_HH_MM_SS));
            sb.append("</div>");
            sb.append("<div>处理时间:");
            sb.append(DateUtil.dateToString(new Date(), DateFormatContent.YYYY_MM_DD_HH_MM_SS));
            sb.append("</div>");
            sb.append("<div>处理凭证:");
            if (StringUtils.hasLength(report.getReportImages())){
                StringBuilder imgSb = new StringBuilder();
                List<String> imgList = StringUtil.stringSpiltList(report.getReportImages(), ",");
                if (!CollectionUtils.isEmpty(imgList)){
                    imgList.stream().forEach(img -> {
                        imgSb.append("<img width='200' height='100' src='");
                        imgSb.append(img);
                        imgSb.append("'/>");
                    });
                }
                sb.append(imgSb.toString());
            }
            sb.append("</div>");
            sb.append("<div>处理结果:");
            sb.append(result);
            sb.append("</div>");
            completableFutureService.runAsyncTask(() -> {
                try {
                    mailSendUtil.send(subject, new String[]{resUser.getEmail()}, sb.toString());
                } catch (MessagingException e) {
                    e.printStackTrace();
                    log.error("【举报处理】:邮件发送失败,to:{}",resUser.getEmail());
                }
            });
        } else if (ReportResultEnum.BIN_USER_ACCOUNT.getCode().equals(handlerCode)){
            // 删帖并封禁用户账号
            removeResourceAndRecycle(resource, dto, r, user, report);
            // 封禁用户账号
            if (resUser.getType() == 1){
                handlerReportInfo(dto, result,1,user);
                r.setCode(200).setMsg("帖子已删除,封禁账号权限不足");
                return;
            }
            User updateUser = new User();
            updateUser.setUserId(resUser.getUserId());
            updateUser.setAvailable(0);
            if (!userService.updateById(updateUser)){
                throw new RspException("处理失败");
            }
            // 处理举报信息表
            handlerReportInfo(dto, result,1,user);
        } else if (ReportResultEnum.REPORT_INVALID_AND_REJECT.getCode().equals(handlerCode)){
            // 举报无效并驳回
            handlerReportInfo(dto, result,2,user);
        }
        r.setCode(200).setMsg("处理成功");
    }

    /**
     * 获取举报详情页
     * @param id
     * @param r
     */
    @Override
    public void getReportDetail(String id, Result r) {
        Report report = reportMapper.selectById(id);
        if (report == null){
            r.setCode(201).setMsg("举报信息不存在");
            return;
        }
        ReportDetailVo vo = new ReportDetailVo();
        BeanUtils.copyProperties(report, vo);

        Integer status = report.getReportStatus();
        String images = report.getReportImages();
        Integer reportUserId = report.getReportUserId();
        Integer resId = report.getResId();
        Integer handlerAdminId = report.getHandlerAdminId();
        // 存在且已经处理完毕
        if (status != null || status != 0){
            if (handlerAdminId != null){
                User admin = userService.getById(handlerAdminId);
                if (admin != null){
                    PublicUserVo userVo = new PublicUserVo();
                    userVo.setUserId(admin.getUserId());
                    userVo.setUserName(admin.getLoginName());
                    userVo.setType(admin.getType());
                    userVo.setAvatar(admin.getAvator());
                    List<Rank> rankList = rankService.getRankList(admin.getUserId());
                    if (!CollectionUtils.isEmpty(rankList)){
                        List<RankVo> list = new ArrayList<>();
                        rankList.stream().forEach(rank -> {
                            RankVo rankVo = new RankVo();
                            BeanUtils.copyProperties(rank, rankVo);
                            list.add(rankVo);
                        });
                        userVo.setRankList(list);
                    }
                    vo.setHandlerAdmin(userVo);
                }
            }
        }
        // 处理举报人信息
        if (reportUserId != null){
            User user = userService.getById(reportUserId);
            if (user != null){
                PublicUserVo userVo = new PublicUserVo();
                userVo.setUserId(user.getUserId());
                userVo.setUserName(user.getLoginName());
                userVo.setType(user.getType());
                userVo.setAvatar(user.getAvator());
                List<Rank> rankList = rankService.getRankList(user.getUserId());
                if (!CollectionUtils.isEmpty(rankList)){
                    List<RankVo> list = new ArrayList<>();
                    rankList.stream().forEach(rank -> {
                        RankVo rankVo = new RankVo();
                        BeanUtils.copyProperties(rank, rankVo);
                        list.add(rankVo);
                    });
                    userVo.setRankList(list);
                }
                vo.setReportUser(userVo);
            }
        }
        // 处理资源
        if (resId != null){
            Resource resource = resourceMapper.selectById(resId);
            if (resource != null){
                ResourceVo resVo = new ResourceVo();
                BeanUtils.copyProperties(resource, resVo);
                if (StringUtils.hasLength(resource.getResImg())){
                    resVo.setResImg(StringUtil.stringSpiltList(resource.getResImg(), ","));
                }
                if (StringUtils.hasLength(resource.getResTags())){
                    resVo.setResTags(StringUtil.stringSpiltList(resource.getResTags(), ","));
                }
                if (resource.getResUserid() != null){
                    User user = userService.getById(resource.getResUserid());
                    if (user != null){
                        ResourceVo.UserVo userVo = new ResourceVo.UserVo();
                        userVo.setUserId(user.getUserId());
                        userVo.setUserName(user.getLoginName());
                        userVo.setAvatar(user.getAvator());
                        List<Rank> rankList = rankService.getRankList(user.getUserId());
                        if (!CollectionUtils.isEmpty(rankList)){
                            List<RankVo> list = new ArrayList<>();
                            rankList.stream().forEach(rank -> {
                                RankVo rankVo = new RankVo();
                                BeanUtils.copyProperties(rank, rankVo);
                                list.add(rankVo);
                            });
                            userVo.setRankList(list);
                        }
                        resVo.setUser(userVo);
                    }
                }
                vo.setResourceVo(resVo);
            }
        }

        if (StringUtils.hasLength(images)){
            vo.setReportImageList(StringUtil.stringSpiltList(images, ","));
        }

        r.setCode(200).setData(vo);

    }

    /**
     * 获得我的举报
     * @param r
     */
    @Override
    public void getMyReport(Result r) {
        User user = AuthCacheService.getUser();
        QueryWrapper<Report> wrapper = new QueryWrapper<>();
        wrapper.eq("report_user_id",user.getUserId())
                .orderByDesc("report_status")
                .orderByDesc("report_push_time");
        List<Report> reports = reportMapper.selectList(wrapper);
        if(CollectionUtils.isEmpty(reports)){
            r.setCode(200).setData(null);
            return;
        }
        r.setCode(200).setData(reports);
    }

    /**
     * 处理举报信息表
     * @param dto
     * @param result
     * @param status
     */
    private void handlerReportInfo(HandlerReportDto dto, String result,Integer status,User admin) {
        // 处理举报信息表
        Report newReport = new Report();
        BeanUtils.copyProperties(dto, newReport);
        newReport.setReportStatus(status);
        newReport.setReportResult(result);
        newReport.setHandlerAdminId(admin.getUserId());
        int update = reportMapper.updateById(newReport);
        if (update != 1){
            throw new RspException("处理失败");
        }
    }

    /**
     * 删除资源添加回收站
     * @param dto
     * @param r
     * @param user
     * @param report
     * @return
     */
    private void removeResourceAndRecycle(Resource resource, HandlerReportDto dto, Result r, User user, Report report) {
        Resource removeRes = new Resource();
        removeRes.setResId(resource.getResId());
        removeRes.setResIsDeleted(1);
        int removeResult = resourceMapper.updateById(removeRes);
        if (removeResult != 1){
            log.error("【举报处理】:处理失败,资源逻辑删除失败,资源:{}",resource.getResId());
            throw new RspException("处理失败");
        }
        RecycleBin recycleBin = new RecycleBin();
        recycleBin.setFileType(2);
        recycleBin.setMainId(resource.getResId());
        recycleBin.setRemoveDate(new Date());
        recycleBin.setOperaAdmin(user.getUserId());
        recycleBin.setRemoveType("举报处理");
        recycleBin.setRemoveWhy(dto.getReportBeizhu());
        int insert = recycleBinMapper.insert(recycleBin);
        if (insert != 1){
            log.error("【举报处理】:处理失败,资源添加回收站删除失败,资源:{}",resource.getResId());
            throw new RspException("处理失败");
        }
    }
}
